﻿#region Using References

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Beaker.OpenCube.Dynamic;
using Beaker.OpenCube.Game;
using Beaker.OpenCube.Specs.Builders;
using Beaker.Services.FileSystem;
using Beaker.Services.FileSystem.Physical;
using Beaker.Services.Locator;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace Beaker.OpenCube.Specs
{
	[TestClass]
	public class DynamicWorldReaderSpecs
	{
		private ManualServiceLocator _serviceLocator;

		[TestInitialize]
		public void Initialize()
		{
			_serviceLocator = new ManualServiceLocator();
			ServiceLocator.SetLocator( _serviceLocator );
		}


	}

	[TestClass]
	public class DynamicGameReaderSpecs
	{
		private ManualServiceLocator _serviceLocator;

		[TestInitialize]
		public void Initialize()
		{
			_serviceLocator = new ManualServiceLocator();
			ServiceLocator.SetLocator( _serviceLocator );
		}

		[TestMethod]
		public void VersionScanning()
		{
			// arrange
			string versionsFolder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft", "versions" );

			IFileSystemService fs = new FileSystemServiceBuilder()
				.WithFile( Path.Combine( versionsFolder, "1.6.1" ), "1.6.1.json", new TextStreamBuilder().WithText( "{\"id\": \"Foo\"}" ).Build() )
				.WithFile( Path.Combine( versionsFolder, "1.6.2" ), "1.6.2.json", new TextStreamBuilder().WithText( "{\"id\": \"Bar\"}" ).Build() )
				.Build();
			_serviceLocator.RegisterSingletonService( fs );

			var game = new DynamicGame();

			// act
			var versions = game.GetInstalledGameVersions().ToArray();

			// assert
			versions.Should().Contain( v => v.Id == "Foo" );
			versions.Should().Contain( v => v.Id == "Bar" );
		}

		[TestMethod]
		public void ProfilesScanning()
		{
			// arrange
			const string json = @"{
			  ""profiles"": {
				""1.6.2"": {
				  ""name"": ""1.6.2"",
				  ""lastVersionId"": ""1.6.2"",
				  ""playerUUID"": ""f2f4e6cb6e034e849d22ef7d4f5e6360""
				},
				""Other Location Test"": {
				  ""name"": ""Other Location Test"",
				  ""gameDir"": ""C:\\Temp\\Minecraft"",
				  ""javaDir"": ""C:\\Program Files\\Java\\jre6\\bin\\javaw.exe"",
				  ""javaArgs"": ""-Xmx1G"",
				  ""resolution"": {
					""width"": 1080,
					""height"": 720
				  },
				  ""allowedReleaseTypes"": [
					""snapshot"",
					""release""
				  ],
				  ""playerUUID"": ""17e56cf4b50242de9ae068df2966bfaa"",
				  ""launcherVisibilityOnGameClose"": ""hide launcher and re-open when game closes""
				}
			  },
			  ""selectedProfile"": ""Other Location Test"",
			  ""clientToken"": ""fd11c80a-d034-4f4d-a832-076618e81afe"",
			  ""authenticationDatabase"": {
				""17e56cf4b50242de9ae068df2966bfaa"": {
				  ""username"": ""OldSkoolUserName"",
				  ""accessToken"": ""37eb39a8607a46cab1adb94b060ea5a2"",
				  ""uuid"": ""17e56cf4b50242de9ae068df2966bfaa"",
				  ""displayName"": ""OldSkool""
				},
				""f2f4e6cb6e034e849d22ef7d4f5e6360"": {
				  ""username"": ""unit@test.com"",
				  ""accessToken"": ""a8addff9db2f4cb38e2a947cd74d1383"",
				  ""uuid"": ""f2f4e6cb6e034e849d22ef7d4f5e6360"",
				  ""displayName"": ""NewAccountType""
				}
			  }
			}";
			string gameFolder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft" );

			IFileSystemService fs = new FileSystemServiceBuilder()
				.WithFile( Path.Combine( gameFolder, "launcher_profiles.json" ), new TextStreamBuilder().WithText( json ).Build() )
				.WithFolder( @"C:\Temp\Minecraft" )
				.WithFile( @"C:\Program Files\Java\jre6\bin\javaw.exe" )
				.Build();
			_serviceLocator.RegisterService( () => fs );

			var game = new DynamicGame();

			// act
			var profiles = game.GetProfiles();

			// assert
			profiles.Profiles.Count.Should().Be( 2 );

			var locations = game.GetProfileLocations().ToArray();
		}

		[TestMethod]
		public void GetGameNamesReturnsNamesOfFoldersInSavesFolderIfLevelDatExistsInIt()
		{
			// arrange
			string someGameFolder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft", "Saves", "SomeGame" );
			string someOtherGameFolder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft", "Saves", "SomeOtherGame" );

			Stream emptyStream = new NbtStreamBuilder()
				.Build();
			IFileSystemService fs = new FileSystemServiceBuilder()
				.WithFile( someGameFolder, "level.dat", emptyStream )
				.WithFile( someOtherGameFolder, "level.dat", emptyStream )
				.Build();
			_serviceLocator.RegisterSingletonService( fs );

			// act
			var gameReader = new DynamicGame();
			IEnumerable<string> names = gameReader.GetWorldFolders().Select( f => f.Name );

			// assert
			names.Should().Contain(
				new[]
				{
					"SomeGame",
					"SomeOtherGame",
				}
			);
		}

		[TestMethod]
		public void GetPlayerNamesReturnNamesOfPlayersInPlayersFolder()
		{
			// arrange
			string folder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft", "Saves", "SomeGame" );
			string playersFolder = Path.Combine( folder, "players" );

			IFileSystemService io = new FileSystemServiceBuilder()
				.WithFile( folder, "level.dat" )
				.WithFile( playersFolder, "Bar.dat" )
				.WithFile( playersFolder, "Foo.dat" )
				.Build();
			_serviceLocator.RegisterSingletonService( io );

			// act
			var gameReader = new DynamicGame();
			IFolder someGame = gameReader.GetWorldFolders().Single( f => f.Name == "SomeGame" );
			DynamicWorld level = gameReader.OpenWorld( someGame );
			string[] names = level.GetPlayerNames().ToArray();

			// assert
			names.Should().Contain(
				new[]
				{
					"Foo", 
					"Bar"
				}
			);
		}

		[TestMethod]
		public void GetPlayerDataWithValidNameShouldReturnPlayerData()
		{
			// arrange
			string someGameFolder = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData ), ".minecraft", "Saves", "SomeGame" );
			string playersFolder = Path.Combine( someGameFolder, "players" );

			Stream emptyStream = new NbtStreamBuilder()
				.Build();
			Stream playerStream = new PlayerDataStreamBuilder()
				.Build();
			IFileSystemService io = new FileSystemServiceBuilder()
				.WithFile( someGameFolder, "level.dat", emptyStream )
				.WithFile( playersFolder, "Foo.dat", playerStream )
				.Build();
			_serviceLocator.RegisterSingletonService( io );

			// act
			var gameReader = new DynamicGame();
			IFolder someGame = gameReader.GetWorldFolders().Single( f => f.Name == "SomeGame" );
			DynamicWorld level = gameReader.OpenWorld( someGame );
			PlayerData data = level.GetPlayerData( "Foo" );

			// assert
			data.Should().NotBeNull();
		}

	}
}
